package com.aabte.auth.account.domain.model;

import com.aabte.auth.account.domain.service.PasswordService;
import com.aabte.auth.group.domain.model.Group;
import com.aabte.auth.shared.model.BaseModelUseLongPK;
import com.aabte.commons.ddd.shared.DomainEntity;
import lombok.Getter;
import lombok.ToString;

import javax.persistence.*;
import java.util.Objects;
import java.util.Set;

import static javax.persistence.ConstraintMode.NO_CONSTRAINT;

@SuppressWarnings("all")
@Entity
@Table(name = "tb_account")
@Getter
@ToString(callSuper = true)
public class Account extends BaseModelUseLongPK implements DomainEntity<Account, AccountId> {

    @Embedded
    private AccountId accountId;

    @Embedded
    private AccountName accountName;

    @Embedded
    private Password accountPassword;

    @Enumerated(value = EnumType.ORDINAL)
    private Status status = Status.ENABLE;

    @ManyToMany
    @JoinTable(name = "tb_account_group", joinColumns = {
            @JoinColumn(name = "account_pk", foreignKey = @ForeignKey(NO_CONSTRAINT))
    }, inverseJoinColumns = {
            @JoinColumn(name = "group_pk", foreignKey = @ForeignKey(NO_CONSTRAINT))
    })
    private Set<Group> groups;

    private Account() {
    }

    private Account(AccountBuilder builder) {
        this.accountId = builder.accountId;
        this.accountName = builder.accountName;
        this.accountPassword = builder.accountPassword;
    }

    @Override
    public boolean sameIdentityAs(Account account) {
        return this.accountId.equals(account.accountId);
    }

    @Override
    public AccountId identity() {
        return this.accountId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account account = (Account) o;
        return sameIdentityAs(account);
    }

    @Override
    public int hashCode() {
        return Objects.hash(accountId);
    }

    public static AccountBuilder builder() {
        return new AccountBuilder();
    }

    public void updatePassword(PasswordService passwordService, Password newPassword) {
        this.accountPassword = passwordService.encryption(newPassword.getPassword());
    }

    public boolean enable() {
        return Status.ENABLE.equals(this.status);
    }

    public static class AccountBuilder {

        private AccountId accountId;
        private AccountName accountName;
        private Password accountPassword;


        public AccountBuilder accountId(AccountId accountId) {
            this.accountId = accountId;
            return this;
        }

        public AccountBuilder accountName(AccountName accountName) {
            this.accountName = accountName;
            return this;
        }

        public AccountBuilder accountPassword(PasswordService passwordService, String password) {
            this.accountPassword = passwordService.encryption(password);
            return this;
        }

        public Account build() {
            return new Account(this);
        }

    }
}
